關於 SameSite Cookie 所帶來的問題,絕大部分有串接外部金物流網站的購物網站,應該都無法避免,還不了解 SameSite 問題的,建議先閱讀 瀏覽器的 SameSite Cookie 對 OpenCart 網站造成的影響 這篇文章。
本篇文章要以 ezShip 台灣便利配 的串接為例,來說明如何解決 SameSite 所造成的問題,以及介紹解決的方法。
ezShip台灣便利配 提供了店到店( 超商取貨/ 超商取貨付款) 配送服務,為首家與OK、萊爾富、全家三大通路合作之店到店( 超商取貨/ 超商取貨付款) 服務平台,當買家從購物平台(如 OpenCart),透過 API 的串接跳轉到 ezShip,選擇要收件的超商門市之後,ezShip 會將買家選取的超商門市相關資料,傳送回購物網站,傳送的 API 相關資料,可參考 http://www.ezship.com.tw/file/ezship_WebOrder_HttpRequest.pdf
由於買家在 ezShip 選好超商門市後,ezShip 是以 post 方式跨站跳轉到購物網站,所以在 SameSite 機制下,將無法同時傳送 cookie 到購物網站,但其實主機端的 Session 值都還是存在的,OpenCart 2.x 的 Session 資料預設是儲存在檔案中,而 OpenCart 3.x 則是改為儲存在資料庫中,你可以檢視資料表中的 oc.session,如下圖。
既然系統無法再從跳轉回來的同時取得 cookie 中的 Session ID,那就改以其他方式,讓網站有辦法在 ezShip 跳轉回來時,取得正確的 Session ID 值即可,做法有很多種,在這裡舉一種方式來介紹,相信大家能觸類旁通,在不同的情境下,思考出適合的應變作法。
我們檢視 ezShip 的串接 API 文件,可以發現傳遞的參數有預留一個 webPara 欄位,可以讓你送到 ezShip 再轉送回來,能作為 Token 驗證功能,事實上大部分的串接 API 規格,都有預留這樣的欄位,有的甚至不只一個欄位。
我們可以利用這個欄位來傳遞 Session ID,如此一來,在轉回 OpenCart 時,就可以取得原本得 Session ID 值了,為了提高安全性,先對 Session 進行編碼再傳送,等回傳後再進行解碼,應該是更理想,不過要注意編碼之後的字串長度,不能超過 API 的限制,免得無法傳送或被裁剪,造成回傳後無法解碼。
最後要修改的是,在 OpenCart 的 Session Class 中,修改判斷 Session ID 的 Cookie 是否存在的邏輯,在讀不到 Cookie 之後,多做一個動作,判斷是否有 $_POST 的 webPara 參數,若有,就進行解碼,若能解碼成功,就把取出的 Session ID 值,指定給 session_id(),如此,OpenCart 就能得到原本的 Session ID 值,繼續正常運作了。
除了將前述 Session ID 編碼後再傳送,以提高安全性之外,另外還能透過其他的資訊驗證,來增加過濾的關卡,例如跳轉離開前,記錄下使用者的 IP (關聯至 Session ID),等轉回時再比對一次,另外,也能在轉回時,檢查 Referer 網址,判斷是否為剛剛跳出的目的網址,或建立白名單來檢查,都是可以讓網站更安全的設置。
上面的作法,不是唯一的應變方法,畢竟每一種串接的情境都未必相同,但個人認為,透過這種類 Token 的模式來解決 SameSite Cookie 問題,是比直接將 Cookie 的 SameSite 設為 None 來的安全,在你的網站還沒開發出理想的解決方式之前,簡單的將 Cookie 改設為 SameSite=None,是可以作為過渡時期的處置方式,但長久之計,還是應該讓 SameSite 機制生效,過濾掉可能的惡意行為,才是比較理想的應變模式。
參考資源
電商系統工程筆記 https://24cc.com/
台灣電商社團 https://www.twec.org/
台灣電商 FB 社團 https://www.facebook.com/groups/opencart.taiwan/
OpenCart 網站代管、客製、維護 https://www.osec.tw/
OpenCart 台灣電商技術支援粉絲頁 https://www.facebook.com/ntcart/
OpenCart 台灣優化版專頁 https://www.osec.tw/opencart.html
OpenCart 台灣中文用戶討論區 https://www.ntcart.com/